package com.jiao.service.impl;

import com.jiao.constants.Constants;
import com.jiao.domain.Result;
import com.jiao.domain.VO.ArticleVo;
import com.jiao.domain.VO.HotArticleVo;
import com.jiao.domain.VO.PageVo;
import com.jiao.domain.entity.Article;
import com.jiao.domain.entity.ArticleCategory;
import com.jiao.domain.entity.Category;
import com.jiao.mapper.ArticleCategoryMapper;
import com.jiao.mapper.ArticleMapper;
import com.jiao.service.ArticleService;
import com.jiao.service.CategoryService;
import com.jiao.utils.BeanCopyUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.jiao.utils.RedisKeyUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {
    @Autowired
    ArticleCategoryMapper articleCategoryMapper;
    @Autowired
    ArticleMapper articleMapper;
    @Autowired
    CategoryService categoryService;
    @Autowired
    RedisTemplate<String,Object> redisTemplate;
    /**
     * 需要查询浏览量最高的前10篇文章的信息。要求展示文章标题和浏览量。把能让用户自己点击跳转到具体的文章详情进行浏览。
     * 注意：不能把草稿展示出来，不能把删除了的文章查询出来。要按照浏览量进行降序排序。
     *
     * 如果说，前端只需要三个字段：文章id,文章名,评论数。所以需要对象拷贝
     */
    @Override
    public Result<List<HotArticleVo>> hotArticleList() {
        // 先查询出来所有的文章。不是草稿，没有删除。浏览量进行降序排序
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Article::getStatus, Constants.ARTICLE_STATUS_NORMAL).orderByDesc(Article::getViewCount);
        //取前10位
        Page<Article> page = new Page<>(1,1);
        page(page,queryWrapper);
        List<Article> articles = page.getRecords();
        //对象拷贝。使用stream流。对于整个对象而言，我只需要文章id,文章名,评论数这三个字段，返回出去
        List<HotArticleVo> hotArticleVoList = new ArrayList<>();
        for (Article article: articles) {
            HotArticleVo hotArticleVo = new HotArticleVo();
            BeanUtils.copyProperties(article, hotArticleVo);
            hotArticleVoList.add(hotArticleVo);
        }

        return Result.success(hotArticleVoList);
    }
    /*
    * 根据文章id取其文章详细数据和其所属分类名
    * */
    @Override
    public Result<ArticleVo> selectArticleListByIds(Long id) {
        //查出文章详细信息
        Article article = articleMapper.selectById(id);
        //查出文章所属分类名
        LambdaQueryWrapper<ArticleCategory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ArticleCategory::getArticleId,id);
        List<ArticleCategory> articleCategories = articleCategoryMapper.selectList(queryWrapper);
        List<Long> CategoryIds = articleCategories.stream().map(ArticleCategory::getCategoryId).collect(Collectors.toList());
        List<String> CategorylistName = categoryService.listByIds(CategoryIds).stream().map(Category::getName).collect(Collectors.toList());
        //封装数据，传给前端
        ArticleVo articleVo = BeanCopyUtils.copyBean(article, ArticleVo.class);
        articleVo.setSummary(CategorylistName);
        return Result.success(articleVo);
    }

    /*
     * 在首页和分类页面都需要查询文章列表。
     * 首页：查询所有的文章
     * 分类页面：查询对应分类下的文章
     * 要求：①只能查询正式发布的文章 ②置顶的文章要显示在最前面
     * */
    @Override
    public Result<PageVo> selectArticleListByCategoryId(Integer pageNum, Integer pageSize, Long categoryId) {
        //1,根据categoryId，取出对应的articleIds
        LambdaQueryWrapper<ArticleCategory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ArticleCategory::getCategoryId,categoryId);
        List<ArticleCategory> articleCategories = articleCategoryMapper.selectList(queryWrapper);
        List<Long> articleIds = articleCategories.stream().map(ArticleCategory::getArticleId).collect(Collectors.toList());
        //2,根据articleIds，去取文章数据，然后对象拷贝
        LambdaQueryWrapper<Article> queryWrapperArticle = new LambdaQueryWrapper<>();
        queryWrapperArticle.in(Article::getId,articleIds).orderByDesc(Article::getIsTop);
        Page<Article> page = new Page<>(pageNum,pageSize);
        page(page,queryWrapperArticle);
        List<Article> articles = page.getRecords();
        List<ArticleVo> articleVos = BeanCopyUtils.copyBeanList(articles, ArticleVo.class);
        //3,返回分页数据
        String name = categoryService.getById(categoryId).getName();
        for (ArticleVo articleVo : articleVos) {
            articleVo.setCategoryName(name);
        }
        PageVo pageVo = new PageVo(articleVos,page.getTotal());
        return Result.success(pageVo);
    }

    /*
    * 获取文章id所对应的阅读量
    * */
    @Override
    public Result<Long> selectViewCount(Long articleId) {
        String viewCountKey = RedisKeyUtil.getViewCountKey(articleId);

        //判断redis有无该文章的阅读量数据，如果不存在，则查找数据库中关于该文章的阅读量记录
        if(Objects.equals(redisTemplate.hasKey(viewCountKey),false)){
            Article article = articleMapper.selectOne(new LambdaQueryWrapper<Article>().eq(Article::getId, articleId));
            //数据库中阅读量数据不为空，那就提取数据库中数据放入缓存中
            if(!Objects.isNull(article)){
                //SETNX
                redisTemplate.opsForValue().setIfAbsent(viewCountKey,article.getViewCount());
            }
        }

        return Result.success(redisTemplate.opsForValue().increment(viewCountKey));
    }
}
